<template>
  <span
    :id="graphNode.id"
    class="v-model-tree-node"
    :class="{ '_drag-hover': isDragOver }"
    :draggable="!graphNode.inEdit"
    @dragend="handleDragEnd"
    @dragstart="handleDragStart"
    @dblclick="handleDbClick"
    @click="handleClickNode"
    @dragover="handleDragOver"
    @drop="handleDrop"
  >
    <span
      class="_icon-rect"
      @contextmenu="handleContextMenu"
    >
      <StatusColorIcon
        v-if="graphNode.data?.baseSt === ('UAF::Projects::Roadmap::ActualProjectMilestone' as StType)"
        :node-data="graphNode.data"
        class="g-pointer"
      ></StatusColorIcon>
      <img
        v-if="modelIcon"
        ref="icon"
        :src="modelIcon"
        alt="icon1"
        onerror="this.src='statics/images/sysml/Stereotype.svg'"
        class="_tree-node-icon g-pointer"
        :class="{ _isCut: isCut }"
      />
      <Tooltip
        v-if="leftExtraIcon.length"
        placement="bottom"
        inlineBlock
        :content="$t(leftExtraIcon.last().label)"
      >
        <img
          :src="leftExtraIcon.last().icon"
          style="height: 16px"
          class="_leftExtraIcon"
        />
      </Tooltip>

      <Tooltip
        v-if="extraIcon.length"
        placement="bottom"
        inlineBlock
        :content="$t(extraIcon.last().label)"
      >
        <img
          :src="extraIcon.last().icon"
          style="height: 16px"
          class="_extraIcon"
        />
      </Tooltip>

      <Tooltip
        v-if="packageLockedIcon"
        placement="bottom"
        inlineBlock
        :content="$t(extraIcon.last().label)"
      >
        <img
          src="statics/icons/app/iconlock.svg"
          title="该包被锁定"
          class="_modelLockedIcon"
        />
      </Tooltip>

      <Tooltip
        v-if="modelsharedIcon"
        placement="bottom"
        inlineBlock
        :content="$t('该模型为共享包')"
      >
        <img
          :src="modelsharedIcon"
          style="height: 16px"
          class="_modelShareIcon"
        />
      </Tooltip>

      <Tooltip
        v-if="modelEncryptIcon"
        placement="bottom"
        inlineBlock
        :content="$t('该模型已封装')"
      >
        <img
          :src="modelEncryptIcon"
          style="height: 16px"
          class="_modelEncryptIcon"
        />
      </Tooltip>

      <Tooltip
        v-if="leftTopIcon"
        placement="bottom"
        inlineBlock
        :content="$t(leftTopIcon.label)"
      >
        <img
          :src="leftTopIcon.icon"
          style="height: 16px"
          class="_leftTopIcon"
        />
      </Tooltip>

      <!-- 批注top点 -->
      <div
        v-if="(commentLevel ?? -1) > -1"
        class="_dot-comment"
        :style="{ background: commentColors?.[commentLevel ?? -1] }"
      ></div>
    </span>
    <el-input
      v-if="graphNode.inEdit"
      ref="nameInput"
      v-model="nameForEdit"
      size="small"
      class="_name-input"
      @blur="handleSaveTitle"
      @keyup.enter="handleSaveTitle"
      @click.stop
    />
    <span
      v-else
      class="g-m-l-4 g-m-tb-2 g-pointer"
      :class="{ _selected: graphNode.selected, _disabled: graphNode.disabled || isProfileEdit }"
      @contextmenu="handleContextMenu"
    >
      <MNodeLabel
        :nodeData="graphNode.data"
        :selected="graphNode.selected"
        :disabled="(graphNode.disabled as boolean) || graphNode.data.usedStatus === UsedStatusValue || isProfileEdit"
        :lock-name="lockName"
      />
      <Tooltip
        v-if="graphNode.data.status === 2 || graphNode.data.status === 7"
        placement="top"
        :content="$t('已被他人锁定')"
        :show-after="500"
        inlineBlock
      >
        <el-icon type="lock" />
      </Tooltip>
    </span>
  </span>
</template>
<script lang="ts">
import { defineComponent, PropType } from "vue";
import { BusEvent, SharedStatus, UsedStatus, ModelType, baseDataTypes, PropertyDataType } from "@/constants/Enums";
import { ProcessType, validationIconRelation, validErrorIconRelation, commentColors } from "@/constants/constants";
import { StType } from "@/constants/StType";
import { actionManager } from "@/action/ActionManager";
import { treeUtil } from "./TreeUtil";
import ContextMenu from "@/common/ContextMenu/index.vue";
import { GraphNode } from "@/modules/model/project/GraphNode";
import { modelService } from "@/modules/model/service";
import MNodeLabel from "./NodeLabel.vue";
import { ActionKey } from "@/action/ActionKey";
import { MetaclassType } from "@/constants/MetaclassType";
import { SortNodeUtil } from "@/modules/model/project/SortNodeUtil";

import { locale } from "@/util/locale";
import { ExtraAttribute, Tooltip, dragUtil, DragSourceType } from "@/mdesign-lib/mdesign-graph.umd.js";
import { ApprovalUsedStatus } from "@/modules/model/service/dto";
// import { DragEventUtil } from "@/util/DragEventUtil";
import StatusColorIcon from "./nodeLabels/StatusColorIcon.vue";

let lastDragOverNode: any;
const iconStatusInfo = {
  [UsedStatus.STATUS_RESUME]: {
    icon: "statics/icons/validate/icon_R.svg",
    label: "恢复元素"
  },
  [UsedStatus.STATUS_AGENT]: {
    icon: "statics/icons/validate/icon_M.svg",
    label: "代理元素"
  }
};
// 鼠标点击树节点，触发重命名时间间隔 ms
const RENAME_CLICK_INTERVAL_TIMEOUT = 500;
let clickTimer = 0;

export default defineComponent({
  name: "comp-tree-node",
  components: {
    MNodeLabel,
    StatusColorIcon,
    Tooltip
  },
  props: {
    graphNode: {
      type: Object as PropType<GraphNode>,
      required: true
    },
    lockName: {
      type: String,
      required: false
    },
    commentLevel: {
      type: Number,
      required: false,
      default: undefined
    }
  },
  data() {
    return {
      nameForEdit: "",
      nameForEditOld: "",
      isDragOver: false,
      sharedStatusValue: SharedStatus.STATUS_SHARED,
      UsedStatusValue: UsedStatus.STATUS_USED,
      commentColors
    };
  },
  computed: {
    modelsharedIcon() {
      const { usedStatus, sharedStatus } = this.graphNode.data;
      if (sharedStatus === SharedStatus.STATUS_SHARED) {
        if (usedStatus === UsedStatus.STATUS_USED) {
          return "statics/icons/validate/iconmodelshare2.svg";
        } else {
          return "statics/icons/validate/iconmodelshare.svg";
        }
      } else {
        return "";
      }
    },
    /**
     * 锁定图标出现在包被锁定的情况下
     * 本人锁定不出现锁定图标
     */
    packageLockedIcon() {
      const { id } = this.graphNode.data;
      const packageStatus = this.graphNode.project?.config.onlineConfig?.packageStatus;
      if (packageStatus && packageStatus[id] && packageStatus[id].LOCKED) {
        return true;
      }
      return false;
    },
    modelEncryptIcon() {
      return this.graphNode.data.isEncrypted ? "statics/icons/app/iconEncrypt.svg" : "";
    },
    leftTopIcon() {
      return iconStatusInfo[this.graphNode.data.usedStatus || ""];
    },
    // 左侧的额外图标
    leftExtraIcon() {
      const result: { label: string; icon: string; level: number }[] = [];
      // 模型校验相关
      const modelShareValidationData = app.activeProject?.ui.modelShareValidationData;
      if (modelShareValidationData?.length) {
        const validation = modelShareValidationData.find(row => row.instanceId == this.graphNode.id);
        if (validation && validation.annoations && validation.annoations.length > 0) {
          validation.annoations.forEach(child => {
            if (child.errorType) {
              result.push({
                label: `${child.errorMessage}  ${child.abbreviation ? "[" + child.abbreviation + "]" : ""}`,
                icon: validErrorIconRelation[child.errorType].icon,
                level: validErrorIconRelation[child.errorType].level
              });
            }
          });
        }
      }
      result.sort((a, b) => a.level - b.level);
      return result;
    },
    // 额外的小图标（最后把所有显示的图标排序，显示优先级最高的图标）
    extraIcon() {
      const result: { label: string; icon: string; level: number }[] = [];
      if (app.activeProject?.config.online) {
        if (app.activeProject.config.onlineConfig.userId === app.global.user?.id) {
          if (this.graphNode.status && this.graphNode.status.LOCKED) {
            result.push({
              label: "节点锁定",
              icon: "statics/icons/app/iconlock.svg",
              level: 4
            });
          }
        }
      }
      const modelValidationData = app.activeProject?.ui.modelValidationData;
      // 模型校验相关
      if (modelValidationData?.length) {
        const validations = modelValidationData.filter(row => row.instanceId == this.graphNode.id);
        validations.forEach(validation => {
          if (validation && validation.annoations && validation.annoations.length > 0) {
            validation.annoations.forEach(child => {
              result.push({
                label: `${child.ruleKey ? locale.t(child.ruleKey) : child.errorMessage}  ${
                  child.abbreviation ? "[" + child.abbreviation + "]" : ""
                }`,
                icon: validationIconRelation[child.severity]?.icon,
                level: validationIconRelation[child.severity]?.level
              });
            });
          }
        });
      }

      // if (this.graphNode.data.usedStatus === UsedStatus.STATUTS_USED && this.graphNode.data.metaclass && [MetaclassType.Package, MetaclassType.Profile].includes(this.graphNode.data.metaclass) && this.graphNode.project.ui.usagePackageMap.has(this.graphNode.id)) {
      if (this.graphNode.project.ui.usagePackageMap.has(this.graphNode.id)) {
        result.push({
          label: "该模型为使用模型",
          icon: "statics/icons/validate/iconmodeluse.svg",
          level: 1
        });
      }

      if (this.graphNode.project.coworkApprovalStatus.readonly && this.graphNode.id === this.graphNode.project.config.rootId) {
        let processName = "下发";
        let processStatus = "审签中";
        if (this.graphNode.project.coworkApprovalStatus.processType === ProcessType.PROJECT_INTEGRATION) {
          processName = "集成";
        }
        if (this.graphNode.project.coworkApprovalStatus.useStatus === ApprovalUsedStatus.IN_USE) {
          processStatus = "审签通过，但未执行" + processName + "操作";
        }
        result.push({
          label: `项目${processName}${processStatus}，当前项目处于受控状态，无法编辑。`,
          icon: "statics/icons/validate/iconControl.svg",
          level: 10
        });
      }
      result.sort((a, b) => a.level - b.level);
      return result;
    },
    modelIcon() {
      if (this.graphNode.data.baseSt === ("UAF::Projects::Roadmap::ActualProjectMilestone" as StType)) {
        return "";
      }
      return this.graphNode.data.icon || "";
    },
    isCut() {
      if (app.global.copyPasteModel.isCut) {
        const nodeId = this.graphNode.id;
        const isCopiedNode = app.global.copyPasteModel.copiedGraphNodes?.find(it => it.id === nodeId);
        if (isCopiedNode) {
          return true;
        }
      }
      return false;
    },
    isProfileEdit() {
      if (app.activeProject?.config?.isProfile) {
        // 扩展包编辑，不允许修改正编辑的扩展包的名称
        const profileModelId = app.global.profileEditProjectIdMapModel.profileNameToProfileModelIdMap.get(
          app.activeProject?.config?.profileName
        ) as string;
        if (profileModelId === this.graphNode.data.id) {
          return true;
        }
      }
      return false;
    }
  },
  watch: {
    "graphNode.inEdit"(val) {
      if (val) {
        this.setInEdit();
      }
    }
  },
  mounted() {
    this.setInEdit();
  },
  methods: {
    handleClickNode(event: MouseEvent) {
      console.log("点击节点", this.graphNode, this.graphNode.visible);
      if (this.graphNode.inEdit) {
        return;
      }

      const project = app.activeProject;
      if (!project) return;
      const nodePool = project.nodePool;

      // 此处判断点击重命名判断
      let currentSelectedNodes = nodePool.getSelectedNodes();
      if (currentSelectedNodes.length === 1 && currentSelectedNodes[0].id === this.graphNode.id) {
        clearTimeout(clickTimer);
        clickTimer = setTimeout(() => {
          const action = actionManager.getAction(ActionKey.setNodeInEdit);
          if (action) {
            action.run(this.graphNode);
            return;
          }
        }, RENAME_CLICK_INTERVAL_TIMEOUT) as any as number;
      }

      // ctrl键进行多选
      if (event.ctrlKey) {
        nodePool.selectionByCtrlKey(this.graphNode.id);
      } else if (event.shiftKey) {
        nodePool.selectionByShiftKey(this.graphNode.id);
      } else {
        // 修改选定node
        nodePool.changeSelectedNodeIds([this.graphNode.id]);
      }

      // 根据选中的id触发属性面板的变更
      currentSelectedNodes = nodePool.getSelectedNodes();
      const selectedNodes = currentSelectedNodes.filter(it => it.data.type !== ModelType.RelationGroup);
      if (!selectedNodes.length) {
        app.$bus.emit(BusEvent.CHANGE_MODEL_DETAIL, null);
      } else if (selectedNodes.length === 1) {
        app.$bus.emit(BusEvent.CHANGE_MODEL_DETAIL, selectedNodes[0].id);
        // console.log(BusEvent.CHANGE_MODEL_DETAIL, selectedNodes[0].id);
      } else {
        app.$bus.emit(
          BusEvent.CHANGE_MODEL_DETAIL,
          undefined,
          undefined,
          selectedNodes.map(it => it.id)
        );
      }
    },
    async handleContextMenu(event: MouseEvent) {
      const project = app.activeProject;
      if (!project) return;
      if (!app.isAppActive) {
        return;
      }
      const selectedNodeIds = app.activeProject.nodePool.selectedNodeIds;
      // 如果当前选中的节点中没有当前节点，则重新选中当前节点
      if (!selectedNodeIds.includes(this.graphNode.id)) {
        const nodePool = project.nodePool;

        // 修改选定node
        nodePool.changeSelectedNodeIds([this.graphNode.id]);
        if (this.graphNode.data.type !== ModelType.RelationGroup) {
          app.$bus.emit(BusEvent.CHANGE_MODEL_DETAIL, this.graphNode.id);
        } else {
          app.$bus.emit(BusEvent.CHANGE_MODEL_DETAIL, null);
        }
      }

      const menu = await treeUtil.getNodeContextMenu(this.graphNode, this.commentLevel);
      if (!menu) return;
      ContextMenu.popup({
        x: event.clientX,
        y: event.clientY,
        menuItems: menu,
        modelId: this.graphNode.id
      })
        .then((menuItem: any) => {
          const action = actionManager.getAction(menuItem.value);
          if (!action) return;
          // TODO
          menuItem.point = {
            x: event.clientX,
            y: event.clientY
          };
          action.onTreeMenuClick?.(this.graphNode, menuItem);
        })
        .catch((e: any) => {
          e && console.error(e);
        });
    },

    async handleDbClick() {
      console.log("DbClick");
      if (this.graphNode.inEdit) {
        return;
      }
      clearTimeout(clickTimer);

      actionManager.getAction(ActionKey.graphNodeDbClick)?.onTreeMenuClick!(this.graphNode, null);
    },

    handleEsc() {
      // this.toPasteNode = [];
    },
    handleDragStart(event: DragEvent) {
      let icon = this.$refs.icon;
      if (!icon) {
        icon = this.$el.querySelector(".v-status-color");
      }
      event.dataTransfer!.setDragImage(icon as Element, -20, 10);
      const nodePool = app.activeProject?.nodePool;
      // 修改bug-6513，场景一：批量拖拽原支持结构是单数，使用了nodePool.selectedNodeIds支持此功能；场景二：对于没有选中的节点，先选中再拖拽
      if (nodePool && !nodePool.selectedNodeIds.includes(this.graphNode.id)) {
        this.handleClickNode(event);
      }
      app.activeProject!.ui.dragModelId = this.graphNode.id;
      app.activeProject!.ui.dragValidCahce = {};

      app.activeProject?.ui.clearSiderBarDropEvents();
      dragUtil.setSourceType(DragSourceType.ModelTreeNode);
      dragUtil.setModelIds(nodePool?.selectedNodeIds || []);
    },
    handleDragEnd() {
      app.activeProject!.ui.dragModelId = "";
      app.activeProject!.ui.dragValidCahce = {};
      app.activeProject?.ui.graphTabs.forEach(tab => {
        tab.treeDropModel?.clear();
        tab.diagramTableEditor?.clearDragStatus();
      });
      if (lastDragOverNode) {
        lastDragOverNode.isDragOver = false;
      }
      dragUtil.clear();
    },

    getNameForEdit() {
      let nameForEdit = this.graphNode.data.name;
      const data = this.graphNode.data;
      const attr = data.showAttribute?.extraAttribute || ({} as ExtraAttribute);
      if (data.metaclass === MetaclassType.Comment) {
        const commentBody = data.showAttribute.extraAttribute?.commentBody;
        nameForEdit = commentBody ? commentBody : "";
      } else if (data.metaclass === MetaclassType.Slot) {
        if (baseDataTypes.includes(attr.slotValueType as PropertyDataType) && attr.slotValues?.length === 1) {
          // 是基本数据类型，并且只有一个才能编辑
          nameForEdit = attr.slotValues[0] + "";
        } else {
          return "";
        }
      } else if (data.baseSt === StType["UIPrototyping::Frame"]) {
        nameForEdit = attr.title || "";
      } else if (
        data.baseSt === StType["UIPrototyping::Label"] ||
        data.baseSt === StType["UIPrototyping::Button"] ||
        data.baseSt === StType["UIPrototyping::TextField"]
      ) {
        nameForEdit = attr.text || "";
      }

      nameForEdit = (nameForEdit || "").replaceAll("\n", " ");
      return nameForEdit;
    },

    shouldStartEdit() {
      if (!this.graphNode.inEdit) return false;

      if (this.graphNode.data.metaclass === MetaclassType.Slot) {
        const attr = this.graphNode.data.showAttribute?.extraAttribute || ({} as ExtraAttribute);

        if (baseDataTypes.includes(attr.slotValueType as PropertyDataType) && attr.slotValues?.length === 1) {
          // 是基本数据类型，并且只有一个才能编辑
        } else {
          return false;
        }
      }

      return true;
    },

    setInEdit() {
      const shouldEdit = this.shouldStartEdit();
      if (!shouldEdit) {
        this.graphNode.inEdit = false;
        return;
      }
      const nameForEdit = this.getNameForEdit();
      this.nameForEdit = nameForEdit;
      this.nameForEditOld = nameForEdit;
      this.$nextTick(() => {
        const input = this.$refs.nameInput as HTMLInputElement;

        if (input) {
          input.focus();
          input.select();
        }
      });
    },

    async handleSaveTitle() {
      if (this.graphNode.inSaveLoading || !this.graphNode.inEdit) return; // 防止blur 与enter重复触发

      if (this.nameForEditOld === this.nameForEdit) {
        this.graphNode.inEdit = false;
        return;
      }

      if (this.nameForEdit.length > 100) {
        app.$notify({
          title: locale.t("构造型名称长度超出限制"),
          type: "warning",
          message: locale.t("构造型名称长度不能大于100个字符")
        });
        this.graphNode.inEdit = false;
        return;
      }

      this.graphNode.inSaveLoading = true;
      await modelService.renameNode(app.activeProject!.id, this.graphNode.id, this.nameForEdit).finally(() => {
        this.graphNode.inSaveLoading = false;
        this.graphNode.inEdit = false;
      });
      this.graphNode.data.name = this.nameForEdit;
    },

    async handleDragOver(event: DragEvent) {
      event.stopPropagation();
      event.preventDefault();
      if (lastDragOverNode) {
        lastDragOverNode.isDragOver = false;
        lastDragOverNode = this;
      } else {
        lastDragOverNode = this;
      }

      this.isDragOver = true;
      const project = app.activeProject;
      if (!project) return;
      const ui = project.ui;
      const dragModelId = ui.dragModelId as string;
      const parentId = this.graphNode.data.id;
      const rootId = this.graphNode.project.config.rootId;
      const selectedNodeIds = project.nodePool.selectedNodeIds;
      let valid = ui.dragValidCahce[parentId] as boolean | "loading";
      if (valid === undefined) {
        if (dragModelId === rootId || this.graphNode.disabled || selectedNodeIds.includes(this.graphNode.id)) {
          valid = false;
          ui.dragValidCahce[parentId] = false;
        } else {
          ui.dragValidCahce[parentId] = true;
          valid = true;
        }
      } else if (valid === "loading") {
        valid = false;
      }
      if (valid) {
        ((event as any).dataTransfer as DataTransfer).dropEffect = "move";
      } else {
        ((event as any).dataTransfer as DataTransfer).dropEffect = "none";
      }
    },
    async handleDrop() {
      const project = app.activeProject;
      if (!project) return;
      this.isDragOver = false;
      let selectedNodeIds = project.nodePool.selectedNodeIds;
      const nodes = selectedNodeIds.map(id => project.nodePool.getNode(id)).filter(Boolean);
      // 检查是否又只读元素，只读元素不能treeDrop
      const disabledNode = nodes.find(it => it && it.disabled);
      if (disabledNode) {
        app.$notify({
          title: "提示",
          type: "error",
          message: "只读元素不可修改"
        });
        return;
      }

      const notRequirementNodes: GraphNode[] = [];
      const requirementNodes: GraphNode[] = [];
      nodes.forEach(node => {
        if (node?.data.baseSt === StType["SysML::Requirements::Requirement"]) {
          requirementNodes.push(node);
        } else {
          notRequirementNodes.push(node as GraphNode);
        }
      });
      requirementNodes.sort((i, j) => {
        return SortNodeUtil.sortByRequirementId(
          i.data.showAttribute.extraAttribute?.requirementId || "",
          j.data.showAttribute.extraAttribute?.requirementId || ""
        );
      });
      selectedNodeIds = [...notRequirementNodes.map(it => it.id), ...requirementNodes.map(it => it.id)];

      await modelService.batchUpdateOwner(project.id, selectedNodeIds, this.graphNode.id);
    }
  }
});
</script>
<style lang="scss">
.v-model-tree-node {
  height: auto;
  padding-top: 0px;
  padding-bottom: 0px;
  display: inline-flex;

  ._icon-rect {
    display: inline-block;
    position: relative;
    width: 16px;
    height: 16px;
    top: 0px;
    left: 2px;
    ._dot-comment {
      position: absolute;
      right: -1px;
      top: 2px;
      bottom: 0px;
      width: 5px;
      height: 5px;
      border-radius: 50%;
    }

    ._tree-node-icon {
      position: relative;
      width: 16px;
      height: 16px;
    }

    ._isCut {
      opacity: 0.3;
    }

    ._leftExtraIcon {
      position: absolute;
      left: -2px;
      bottom: -6px;
      width: 8px;
      height: 8px;
    }

    ._leftTopIcon {
      position: absolute;
      left: 0;
      top: 2px;
      width: 16px;
      height: 16px;
    }

    ._extraIcon {
      position: absolute;
      right: -2px;
      bottom: -6px;
      width: 8px;
      height: 8px;
    }

    ._modelShareIcon {
      position: absolute;
      right: 0px;
      bottom: -6px;
      width: 14px;
      height: 14px;
      z-index: 999;
    }
    ._modelLockedIcon {
      position: absolute;
      right: -2px;
      bottom: -2px;
      width: 8px;
      height: 8px;
      z-index: 999;
    }
    ._modelEncryptIcon {
      position: absolute;
      right: 0px;
      bottom: -6px;
      width: 14px;
      height: 14px;
      z-index: 999;
    }

    // .shared_node {

    //   right: 0;
    //   position: absolute;
    //   bottom: -2px;
    //   width: 8px;
    //   height: 8px;

    // }

    ._profile-update-icon {
      position: absolute;
      right: 1px;
      bottom: 0;
      width: 6px;
      height: 6px;
    }
  }

  ._name-input {
    height: 18px;
    font-size: 12px;
    line-height: 18px;
    width: 128px;
    margin-left: 8px;
    border-radius: 0px;

    .el-input__inner {
      height: 18px;
      font-size: 12px;
      line-height: 18px;
    }
  }

  &._drag-hover {
    background: var(--md-primary-color);

    .v-model-tree-node-label._is-new {
      ._name-label {
        color: #202020;
      }
    }

    * {
      pointer-events: none;
    }
  }

  &._hidden {
    display: none;
  }
}
</style>
